package com.ai.helper;

import org.springframework.stereotype.Service;
import org.vosk.Model;
import org.vosk.Recognizer;

import javax.sound.sampled.*;
import java.io.File;
import java.io.IOException;

/**
 * 新的助手控制器
 *
 * @author houwenpeng
 */
@Service
public class HelpService {

    private static final String WAKE_WORD = "同学";
    private static final String VOSK_MODEL_PATH ="D:\\project\\AI\\src\\main\\resources\\model\\vosk-model-cn-0.22"; // vosk-model-small-cn-0.22"， vosk-model-cn-kaldi-multicn-0.15 ，vosk-model-en-us-0.22
    private static final String PROMPT_AUDIO_PATH ="D:\\project\\AI\\src\\main\\resources\\system.wav";
    private static final float PITCH_FACTOR = 1.0f;
    private Model voskModel;

    // 初始化 Vosk 模型
    public HelpService() {
        try {
            // 加载 Vosk 免费模型
            voskModel = new Model(VOSK_MODEL_PATH);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 开始录音
     * @return
     */
    public String startListening() {
        while (true) {
          return  record();
        }
    }


    /**
     *  录音监听的方法
     * @return
     */
    public String record() {
        // 初始化音频格式，降低采样率以减慢播放速度
        final AudioFormat audioFormat = new AudioFormat(
                AudioFormat.Encoding.PCM_SIGNED,// 编码格式
                8000.0F, // 采样率
                16, // 位深度
                1, // 通道数
                2,  // 帧大小
                8000.0F, // 帧速率
                false);

//        final AudioFormat audioFormat = new AudioFormat(
//                AudioFormat.Encoding.PCM_SIGNED,// 编码格式
//                44100.0F, // 采样率
//                16, // 位深度
//                1, // 通道数
//                2,  // 帧大小
//                44100.0F, // 帧速率
//                false);

        // 获取音频输入设备信息
        DataLine.Info info = new DataLine.Info(TargetDataLine.class, audioFormat);
        try {
            // 获取并打开音频输入设备
            final TargetDataLine targetDataLine = (TargetDataLine) AudioSystem.getLine(info);
            // 打开音频输入设备
            targetDataLine.open(audioFormat);
            // 开始录音
            targetDataLine.start();
            System.out.println("监听已唤醒~~");
            // 创建识别器
            Recognizer recognizer = new Recognizer(voskModel, 8000);
            // 创建缓冲区
            byte[] buffer = new byte[4096];

            // 监听唤醒词
            while (true) {
                // 从音频输入设备读取数据
                int bytesRead = targetDataLine.read(buffer, 0, buffer.length);
                // 传递数据给识别器
                if (recognizer.acceptWaveForm(buffer, bytesRead)) {
                    // 获取识别结果
                    String result = recognizer.getResult();
                    // 如果包含唤醒词，播放提示音并开始录音
                    if (result.contains(WAKE_WORD)) {
                        System.out.println("唤醒成功~~");
                        // 播放提示音
                        playAudio(PROMPT_AUDIO_PATH,PITCH_FACTOR);
                        System.out.println("你好主人,有什么可以为你服务的?");
                        // 开始录音
                        startRecording(targetDataLine, recognizer);
                        break;
                    }
                }
            }

            // 关闭识别器
            recognizer.close();

            // 关闭音频输入设备
            targetDataLine.stop();
            targetDataLine.close();

        } catch (Exception ex) {
            ex.printStackTrace();
        }
        // 返回录音文件路径
        return "D:\\project\\AI\\cyborg.wav";
    }

    /**
     *  语音
     * @param filePath  wav 格式文件
     * @param pitchFactor  1.0 表示正常音高，大于 1.0 升高音高，小于 1.0 降低音高
     */
    public void playAudio(String filePath, float pitchFactor) {
        try {
            // 创建音频文件
            File audioFile = new File(filePath);
            // 创建音频输入流和音频格式
            AudioInputStream audioStream = AudioSystem.getAudioInputStream(audioFile);
            AudioFormat originalFormat = audioStream.getFormat();

            // 创建一个新的音频格式，用于改变音高
            AudioFormat newFormat = new AudioFormat(
                    originalFormat.getEncoding(),
                    originalFormat.getSampleRate() * pitchFactor,
                    originalFormat.getSampleSizeInBits(),
                    originalFormat.getChannels(),
                    originalFormat.getFrameSize(),
                    originalFormat.getFrameRate() * pitchFactor,
                    originalFormat.isBigEndian()
            );

            // 将原始音频流转换为新格式的音频流
            AudioInputStream changedStream = AudioSystem.getAudioInputStream(newFormat, audioStream);

            // 创建数据行信息
            DataLine.Info info = new DataLine.Info(Clip.class, newFormat);
            // 获取并打开音频数据行
            Clip audioClip = (Clip) AudioSystem.getLine(info);
            // 打开音频数据行
            audioClip.open(changedStream);

            // 开始播放
            audioClip.start();

            // 等待播放完成
            while (!audioClip.isRunning()) {
                Thread.sleep(100);
            }
            // 等待播放完成
            while (audioClip.isRunning()) {
                Thread.sleep(100);
            }

            // 关闭音频数据行和音频输入流
            audioClip.close();
            changedStream.close();
            audioStream.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 开始录音
     * @param targetDataLine
     * @param recognizer
     */
    private void startRecording(TargetDataLine targetDataLine, Recognizer recognizer) {
        try {
            // 创建音频输入流和文件
            AudioInputStream audioInputStream = new AudioInputStream(targetDataLine);
            // 创建文件
            File file = new File("cyborg.wav");
            // 启动线程写入音频文件
            Thread saveThread = new Thread(() -> {
                try {
                    // 写入音频文件
                    AudioSystem.write(audioInputStream, AudioFileFormat.Type.WAVE, file);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });

            // 启动线程
            saveThread.start();

            // 记录用户最后一次语音活动的时间
            long lastActivityTime = System.currentTimeMillis();
            // 超时时间
            long timeout = 5000;
            // 创建缓冲区
            byte[] buffer = new byte[4096];

            // 开始录音
            while (true) {
                // 传递数据给识别器
                int bytesRead = targetDataLine.read(buffer, 0, buffer.length);
                // 传递数据给识别器
                if (recognizer.acceptWaveForm(buffer, bytesRead)) {
                    // 获取识别结果
                    String result = recognizer.getResult();
                    // 如果结果不为空，则打印识别结果
                    if (!result.trim().isEmpty()) {
                        System.out.println("识别结果：" + result);
                        lastActivityTime = System.currentTimeMillis(); // 更新最后活动时间
                    }
                }

                // 检查是否超时
                if (System.currentTimeMillis() - lastActivityTime > timeout) {
                    System.out.println("用户停顿 5 秒，停止录音。");
                    break;
                }

                try {
                    Thread.sleep(100); // 减少资源消耗
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            // 停止并关闭录音
            targetDataLine.stop();
            targetDataLine.close();
            System.out.println("录音完成~~");

            // 等待保存线程完成
            saveThread.join();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

}
